package com.study.sequence.service.impl;

import com.study.common.annotation.MyReference;
import com.study.common.annotation.MyService;
import com.study.sequence.api.ISequencerviceApi;
import com.study.sequence.bean.SequenceBuffer;
import com.study.sequence.bean.SequenceData;
import com.study.sequence.common.CommonConstract;
import com.study.sequence.dto.SequenceDTO;
import com.study.sequence.service.IFlushService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by 张波 on 2020/5/23.
 */
@Slf4j
@Component
@MyService
public class FlushServiceImpl implements IFlushService {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    @MyReference
    private ISequencerviceApi sequencerviceApi;

    /*刷新比例值*/
    @Value("${SEQUENCE.PROPORTION:0.2}")
    private float proportion;
    @Value("${SEQUECNT.FLUSH.TIME.SECOND:30}")
    private int flushTimeSecond;

    /**
     * 初始化sequence
     *
     * @param businessKey
     * @return
     */
    @Override
    public SequenceData init(String businessKey) {
        businessKey = StringUtils.isBlank(businessKey) ? CommonConstract.DEFAULT_BUSINESS_KEY : businessKey;
        /*构建sequeceDTO对象，并检验是否进行初始化*/
        SequenceData sequenceData = new SequenceData(businessKey, this,proportion,flushTimeSecond);
        if (!sequenceData.isInit()) {
            SequenceDTO sequence = sequencerviceApi.getSequence(businessKey);
            sequenceData.init(sequence.getValueSize(), sequence.getCurrentValue(), sequence.getStepValue());
        }
        return sequenceData;
    }


    /**
     * 刷新sequence
     *
     * @param sequenceData
     * @return
     */
    @Override
    public boolean flush(SequenceData sequenceData) {
        try {
            log.info("进入缓存刷新逻辑");
            sequenceData.getFlushLock().lock();
            log.info("进入缓存刷新逻辑，成功获取到锁！");
            sequenceData.setFlushTime(LocalDateTime.now());
            SequenceBuffer sequenceBuffer = sequenceData.getBufferFlag().get() ? sequenceData.getSequenceBuffer_B() : sequenceData.getSequenceBuffer_A();
            if (sequenceBuffer.getFlush().get()) {
                /*如果已经刷新了，则不再进行操作*/
                return false;
            }
            if (sequenceBuffer.getIsInit().get() && !sequenceBuffer.isFlus(sequenceData.getProportion())) {
                /*检验是否达到了刷新buffer阈值*/
                return false;
            }
            SequenceDTO sequence = sequencerviceApi.getSequence(sequenceData.getBusinessKey());
            sequenceBuffer.reset(sequence.getCurrentValue());
            /*如果刷新成功了，则更新刷新时间，刷新状态*/
            sequenceData.getIsFlus().compareAndSet(false, true);
            boolean flag = sequenceData.getBufferFlag().get();
            sequenceData.getBufferFlag().compareAndSet(flag, !flag);
        } catch (Exception e) {
            log.error("序列刷新失败:{}", e);
        } finally {
            /*重置线程刷新状态，让后续调度请求再来进行刷新*/
            sequenceData.getThreadFlus().compareAndSet(true, false);
            sequenceData.getFlushLock().unlock();
            log.info("刷新完成，释放锁");
        }
        return true;
    }


}
